/*Author: Rony Lahav (ID:043489889)*/

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.HashMap;
import java.util.SortedMap;


public class MainSNLocator implements Runnable{

	String msg;
	private static DatagramSocket ds = final_project.mainUDPSoc;
	boolean fromSNList = true;
	SortedMap<String, DBTuple> list=null;
	long uniqueID;
	
	public MainSNLocator(long id){
		msg=MessageCenter.getInstance().createMessage_AV();
		this.uniqueID=id;
	}
	
	public void run(){
		list = DataBase.getInstance().getSnList();
		if (list == null){ //first connection
			list = DataBase.getInstance().getAllTuples();
			fromSNList=false;
		}
		goThroughList();
		if (!iGotAMainSN() && !final_project.inFallBackMode && fromSNList){ //check records from my original list
			//could be unknown tuples that are SNs, all records known as SNs were already checked in SNLIST (or they wouldn't have been known to be SNs)
			list = DataBase.getInstance().getAllRegTuples();
			goThroughList();
		}
		if (!iGotAMainSN() && !final_project.inFallBackMode)	//went through all records without available SNs => FALLBACK mode
			final_project.goToFallBackMode();
		final_project.removeThreadFromLivingList(uniqueID);
	}
	
	private void goThroughList(){
		Collection<DBTuple> c = list.values();
		for (DBTuple tuple : c) {
			UDPSend(tuple);
			try {
				//in this time the UDPListener will process incoming SNLIST from this SN if he replies with one 
				Thread.sleep(final_project.timeout);
			} catch (InterruptedException e) {}
			if (iGotAMainSN() || final_project.inFallBackMode)
				break;
			else if (fromSNList){	//update as SN in my original list (SNLIST updates in snListMap only)
				tuple.setStatus("0");
				tuple.setIsSN(true);
				tuple.setIsMainSN(false);
				DataBase.getInstance().updateExistingTuple(tuple);
			}
		}
	}
	
	/**
	 * This method creates a UDP message and sends it through the socket to the relevant SN
	 */
	private void UDPSend(DBTuple tupleForSending) {
		try {
			if (!final_project.isShutDown()){
				DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.length(), InetAddress.getByName(tupleForSending.getPeerIP()),Integer.parseInt(tupleForSending.getUdpPort()));
				ds.send(dp); // send the message to the peer
			}
		}
		catch (SocketTimeoutException e1){
			if (ds != null && !ds.isClosed()){
				ds.close();
			}
		}
		catch (IOException e2){}
	}

	private boolean iGotAMainSN(){
		DBTuple myMainSN=final_project.getMyMainSN();
		if (myMainSN!=null && myMainSN.getStatus())
			return true;
		else
			return false;
	}
}
